/*
 * Bag.cpp
 *
 *  Created on: 2013. 9. 9.
 *      Author: jjaehuny
 */

#include "Bag.h"
#include "Item.h"
#include "Static.h"
#include "Function.h"
#include "../User.h"
#include "../NResource/ItemResource.h"
#include "../NResource/Static.h"
#include "../NState/Static.h"

#include <Database/Static.h>

namespace ProjectZ { namespace NLogic {

Bag::Bag(User * pUser, int eBagType) : _user(pUser), _clsItemVector(0), _bLoad(false), _bDecreaseBattlepetStamina(false), _itemCount(0), _eBagType(eBagType), _maxSlotCount(0)
{
	_maxSlotCount = NLogic::NFunction::GetBagSlotMaxOpenCount(static_cast<INVEN_BAG_TYPE>(eBagType));
//	_clsItemVector.reserve(_maxSlotCount);
//
//	for(int i = 0; i < _maxSlotCount; ++i)
//	{
//		_clsItemVector[i] = NULL;
//	}

//	//_clsItemVector.reserve(_maxSlotCount);
//	_clsItemVector.clear();

//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		_clsItemVector[i] = NULL;
//	}
}

Bag::~Bag() {
	Finalize();
}

void
Bag::Initialize()
{
	//_clsItemVector.clear();

	_bLoad = false;
}

void
Bag::Finalize()
{
//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		if (NULL != _clsItemVector[i])
//		{
//			NLogic::Static::InstancePtr()->DEL_ITEM( _clsItemVector[i] );
//			_clsItemVector[i] = NULL;
//		}
//	}
//
//	_clsItemVector.clear();
//	_bLoad = false;

	//std::for_each(_clsItemVector.begin(), _clsItemVector.end(), [&]())

//	int idx = HasItemCount();
//	if (idx > _maxSlotCount)
//	{
//		DEBUGLOG("%s HasItemCount : %d _maxSlotCount : %d", HasItemCount(), _maxSlotCount);
//		idx = _maxSlotCount;
//	}
//
//	for (int i = 0; i < idx; ++i)
//	{
//		if (NULL == _clsItemVector[i])
//			continue;
//
//		NLogic::Static::InstancePtr()->DEL_ITEM(_clsItemVector[i]);
//		_clsItemVector[i] = NULL;
//	}

	Item * pItem = NULL;
	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem)
		{
			NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
		}
	}
	_clsItemVector.clear();
	_bLoad = false;
}

bool
Bag::AddItem(Item * pItem)
{
//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		if (NULL == _clsItemVector[i])
//		{
//			_clsItemVector[i] = pItem;
//			pItem->GetData().bag_slot_number = i;
//			return true;
//		}
//	}

	if (this->HasItemCount() >= _maxSlotCount)
	{
		return false;
	}

//	if (true == IsExistItem(pItem->GetItemSeq()))
//	{
//		DEBUGLOG("true == IsExistItem(pItem->->GetItemSeq() ITEM SEQ = %ld", pItem->GetItemSeq());
//	}
//	else
	{
		_clsItemVector.push_back(pItem);
	}
	return true;

//	int index = 0;
//	for (int i = 0 ; i < s_MAX; ++i)
//	{
//		if (NULL == _clsItemVector[i])
//		{
//			_clsItemVector[index] = pItem;
//			return i;
//		}
//	}

//	for (ITEMVECTOR::iterator it = _clsItemVector.begin(); it != _clsItemVector.end(); ++it)
//	{
//		Item* pItem = *it;
//		if (NULL == pItem)
//		{
//			_clsItemVector[index] = pItem;
//			pItem->GetData().bag_slot_number = index;
//			// 현재 소지한 아이템에 개수를 증가 시킨다.
//			++_itemCount;
//			return true;
//		}
//		++index;
//	}
}

Item *
Bag::GetItem(uint64_t ItemSeq)
{
//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		Item* pItem = _clsItemVector[i];
//		if (NULL != pItem && _clsItemVector[i]->GetItemSeq() == ItemSeq)
//		{
//			return pItem;
//		}
//	}

	Item * pItem = NULL;
	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
		{
			return pItem;
		}
	}

	return NULL;

//	for (int i = 0; i < HasItemCount(); ++i)
//	{
//		Item* pItem = _clsItemVector[i];
//		if (NULL != pItem && _clsItemVector[i]->GetItemSeq() == ItemSeq)
//		{
//			return pItem;
//		}
//	}

//	for (ITEMVECTOR::iterator it = _clsItemVector.begin(); it != _clsItemVector.end(); ++it)
//	{
//		Item* pItem = *it;
//		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
//		{
//			return pItem;
//		}
//	}

//	return NULL;
}

Item *
Bag::GetStackItem(const Item::Data & data)
{
//	for (int i = 0; i < _maxSlotCount; ++i)
//	{
//		Item * pItem = _clsItemVector[i];
//		if (NULL != pItem && pItem->GetData().sub_type == data.sub_type && pItem->GetData().tid == data.tid)
//		{
//			return pItem;
//		}
//	}


	Item * pItem = NULL;
	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL == pItem)
			continue;

		if (pItem->GetData().sub_type != data.sub_type)
			continue;

		if (pItem->GetData().tid != data.tid)
			continue;

		if (pItem->GetData().quantity >= 99)
			continue;

		if (1 != NResource::Static::Instance().GetItemResource()->getItemStackType(pItem->GetData()))
			continue;

		return pItem;
	}

	return NULL;


#if 0
	for (int i = 0; i < HasItemCount(); ++i)
	{
		Item * pItem = _clsItemVector[i];

		if (NULL == pItem)
			continue;

		if (pItem->GetData().sub_type != data.sub_type)
			continue;

		if (pItem->GetData().tid != data.tid)
			continue;

		if (pItem->GetData().quantity >= 99)
			continue;

		return pItem;
	}

	return NULL;
#endif
}

//Item *
//Bag::GetItemFromIndex(int index)
//{
//	if (index < 0 || index > _maxSlotCount)
//		return NULL;
//
//	return _clsItemVector[index];
//}

Item *
Bag::PopItem(uint64_t ItemSeq)
{
//	for (ITEMVECTOR::iterator it = _clsItemVector.begin(); it != _clsItemVector.end(); ++it)
//	{
//		Item* pItem = *it;
//		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
//		{
//			this->_clsItemVector[pItem->GetData().bag_slot_number] = NULL;
//			return pItem;
//		}
//	}



	Item * pItem = NULL;

	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
		{
			_clsItemVector.erase(itr);
			return pItem;
		}
	}

	return NULL;
}

bool
Bag::IsBagFull()
{
	if (_maxSlotCount <= HasItemCount())
	{
		return true;
	}

	return false;
}

int
Bag::RemainBagSlotCount()
{
	return _maxSlotCount - HasItemCount();
}

bool
Bag::IsExistItem(uint64_t ItemSeq)
{
	bool bFound = false;
	Item * pItem = NULL;

	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
		{
			//_clsItemVector.erase(itr);
			bFound = true;
			break;
		}
	}

	return bFound;

#if 0
	for (int i = 0 ; i < HasItemCount(); ++i)
	{
		Item* pItem = _clsItemVector[i];
		if (NULL != pItem && pItem->GetItemSeq() == ItemSeq)
		{
			return true;
		}
	}

	return false;
#endif
}

//bool
//Bag::ChangeItemSlot(int srcIndex, int dstIndex)
//{
//	Item * pSrcItem = _clsItemVector[srcIndex];
//	if (pSrcItem == NULL)
//		return false;
//
//	Item * pDstItem	= _clsItemVector[dstIndex];
//	if (pDstItem != NULL)
//		return false;
//
//	pSrcItem->GetData().bag_slot_number	= dstIndex;
//
//	_clsItemVector[dstIndex] = pSrcItem;
//	_clsItemVector[srcIndex] = NULL;
//
//	return true;
//}

//int
//Bag::FindEmptyItemSlot() const
//{
//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		if (NULL == _clsItemVector[i])
//		{
//			return i;
//		}
//	}
//	return -1;
//}

int
Bag::HasItemCount()
{
//	int count = 0;
//
//	for (int i = 0 ; i < _maxSlotCount; ++i)
//	{
//		Item* pItem = _clsItemVector[i];
//		if (NULL != pItem)
//		{
//			count++;
//		}
//	}
//
//	return count;

	return static_cast<int>(_clsItemVector.size());
}

bool
Bag::ItemLoadFromDatabase()
{
	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::SELECT);

	if (BAG_TYPE_WAREHOUSE == _eBagType)
	{
		clsAuto->MakeQuery("SELECT * FROM info_item WHERE user_seq = %d AND bag_type = %d AND status = 0",
				_user->GetUserSeq(), _eBagType);
	}
	else
	{
		clsAuto->MakeQuery("SELECT * FROM info_item WHERE character_seq = %d AND bag_type = %d AND status = 0",
				_user->GetCharacterInfo().characterseq, _eBagType);
	}

	if (false == ::Database::GETSESSION()->SyncExecute(_user->GetUserInfo().shard_Item_db_type, clsAuto))
		return false;

	if( clsAuto->GetErrorIdx() != 0 )
		return false;

	if (0 == clsAuto->ResultRowCount())
	{
		_bLoad = true;
		return true;
	}

	while( clsAuto->Next() )
	{
		int64_t seq = 0;
		int userseq = 0;
		int characterseq = 0;
		int status = 0;

		clsAuto->GetRecord() >> seq >> userseq >> characterseq >> status;

		Item::Data clsData;
		clsAuto->GetRecord() >> clsData.bag_type;
		clsAuto->GetRecord() >> clsData.bag_slot_number;
		clsAuto->GetRecord() >> clsData.quantity;
		clsAuto->GetRecord() >> clsData.class_type;
		clsAuto->GetRecord() >> clsData.sub_type;
		clsAuto->GetRecord() >> clsData.tid;
		clsAuto->GetRecord() >> clsData.iconidx;
		clsAuto->GetRecord() >> clsData.item_type;
		clsAuto->GetRecord() >> clsData.cur_duration;
		clsAuto->GetRecord() >> clsData.max_duration;
		clsAuto->GetRecord() >> clsData.set_type;
		clsAuto->GetRecord() >> clsData.non_identity;
		clsAuto->GetRecord() >> clsData.cur_refine_step;
		clsAuto->GetRecord() >> clsData.quality;
		clsAuto->GetRecord() >> clsData.level;

		for (int i = 0; i < 7; ++i)
		{
			clsAuto->GetRecord() >> clsData.eff_type[i];
			clsAuto->GetRecord() >> clsData.eff_pos[i];
			clsAuto->GetRecord() >> clsData.eff_value[i];
		}

		clsAuto->GetRecord() >> clsData.open_upgrade_stone_slot;
		clsAuto->GetRecord() >> clsData.ability_enhance_rate;
		clsAuto->GetRecord() >> clsData.max_enhance_step;
		clsAuto->GetRecord() >> clsData.buy_use;
		clsAuto->GetRecord() >> clsData.evolve_step;
		clsAuto->GetRecord() >> clsData.evolve_max;
		clsAuto->GetRecord() >> clsData.evolve_point;
		clsAuto->GetRecord() >> clsData.evolve_percent;
		clsAuto->GetRecord() >> clsData.evolve_value;
		clsAuto->GetRecord() >> clsData.reg_date;

		Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
		pItem->Open_FromDatabase(seq, clsData, _user);

		//DEBUGLOG("+++ ITEMLOAD bag=%d, slot=%d", _eBagType, clsData.bag_slot_number);
//
//		this->_clsItemVector[pItem->GetData().bag_slot_number] = pItem;
//		++_itemCount;

//		if (true == IsExistItem(pItem->GetItemSeq()))
//		{
//			DEBUGLOG("true == IsExistItem(pItem->->GetItemSeq() ITEM SEQ = %ld", pItem->GetItemSeq());
//		}
//		else
		{
			_clsItemVector.push_back(pItem);
		}

	}

	_bLoad = true;
	return true;
}

bool
Bag::ItemLoadFromDatabase_Asyn()
{
	Database::Command * pCommand = Database::GETCOMMANDPOOL()->NEW();

	pCommand->SetQueryType(::Database::Command::S_PROCEDURE);
	if (BAG_TYPE_WAREHOUSE == _eBagType)
	{
		pCommand->MakeQuery("SELECT * FROM info_item WHERE user_seq = %d AND bag_type = %d AND status = 0",
				_user->GetUserSeq(), _eBagType);
	}
	else
	{
		pCommand->MakeQuery("SELECT * FROM info_item WHERE character_seq = %d AND bag_type = %d AND status = 0",
				_user->GetCharacterInfo().characterseq, _eBagType);
	}

	pCommand->SetObserver(_user);

	if (false == Database::GETSESSION()->AsyncExecute(_user->GetUserInfo().shard_Item_db_type, pCommand))
	{
//		DEBUGLOG("%s : AsyncExecute Fail", __FUNCTION__);
//
//		SendFailMarketItemSaleList(pUser, ACK_DB_ERROR);
//		pUser->SetState(NState::Static::Instance().MAINFRIENDLIST());

		Database::GETCOMMANDPOOL()->DEL(pCommand);

		return false;
	}

	_user->SetLoadBagTypeSeq(_eBagType);
	_user->SetState(NState::Static::Instance().WAITITEMINFO());

	return true;
}

Item *
Bag::AddItemWithData(Item::Data & data, bool & bBagFull, bool bOpenNone)
{
	// 아이템 스택 여부 확인

	if (1 == NResource::Static::Instance().GetItemResource()->getItemStackType(data))
	{
		Item * pItem = this->GetStackItem(data);
		if (pItem != NULL)
		{
			int quantity = pItem->GetData().quantity + data.quantity;

			if (quantity <= 99)
			{
				pItem->GetData().quantity = quantity;
				pItem->UpdateDatabaseItemInfo();
				return pItem;
			}

			bBagFull = false;
			if (true == IsBagFull())
			{
				bBagFull = true;
				return NULL;
			}

			pItem->GetData().quantity = 99;
			pItem->UpdateDatabaseItemInfo();
			data.quantity = quantity - 99;
		}
	}

//	int slotIndex = FindEmptyItemSlot();
//	if (-1 == slotIndex)
//		return NULL;

	bBagFull = false;
	if (true == IsBagFull())
	{
		bBagFull = true;
		return NULL;
	}

	Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
	if (NULL == pItem)
	{
		DEBUGLOG("%s : pItem is NULL!!!", __FUNCTION__);
		return NULL;
	}

	if (true == bOpenNone)
	{
		pItem->Open_None(data, _user);
	}
	else if (NResource::Static::Instance().GetItemResource()->isUpstone(data))
	{
		pItem->Open_UpStone(data, _user);
	}
	else if (NResource::Static::Instance().GetItemResource()->isFairy(data) || NResource::Static::Instance().GetItemResource()->isBattlePet(data))
	{
		pItem->Open_Fairy(data, _user);
	}
	else
	{
		pItem->Open_Normal(data, _user);
	}

//	_clsItemVector[slotIndex] = pItem;
//	pItem->GetData().bag_slot_number = slotIndex;

	if (false == pItem->InsertToDatabaseItemInfo())
	{
		//_clsItemVector[slotIndex] = NULL;
		DEBUGLOG("%s : false == pItem->InsertToDatabaseItemInfo()", __FUNCTION__);
		NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
		return NULL;
	}

	AddItem(pItem);

	return pItem;
}

bool
Bag::IsExistSameItem(const Item::Data& data)
{

	bool bFound = false;
	Item * pItem = NULL;

	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem && data.sub_type == pItem->GetData().sub_type && data.tid == pItem->GetData().tid)
		{
			//_clsItemVector.erase(itr);
			bFound = true;
			break;
		}
	}

	return bFound;



#if 0
	for (int i = 0; i < HasItemCount(); i++)
	{
		Item * pItem = _clsItemVector[i];
		if (NULL == pItem)
			continue;

		if (data.sub_type == pItem->GetData().sub_type
				&& data.tid == pItem->GetData().tid)
		{
			return true;
		}
	}

	return false;
#endif
}

Item *
Bag::GetIdentifyScroll()
{
	Item * pItem = NULL;

	ITEMVECTOR::iterator itr = _clsItemVector.begin();
	for (; itr != _clsItemVector.end(); ++itr)
	{
		pItem = ( * itr );
		if (NULL != pItem && 5 == pItem->GetData().tid && CLASS_ITEM_TABLE_CHARGE == pItem->GetData().sub_type)
		{
			return pItem;
		}
	}

	return NULL;


#if 0
	for (int i = 0; i < HasItemCount(); i++)
	{
		Item * pItem = _clsItemVector[i];
		if (NULL == pItem)
			continue;

		if (5 == pItem->GetData().tid
				&& CLASS_ITEM_TABLE_CHARGE == pItem->GetData().sub_type)
		{
			return pItem;
		}
	}

	return NULL;
#endif
}

void
Bag::DecreaseBattlePetStamina()
{
	_bDecreaseBattlepetStamina = true;

	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::S_PROCEDURE);
	clsAuto->MakeQuery("call sp_update_battlepet_stamina(%d)", _user->GetCharacterInfo().characterseq);

	if (false == ::Database::GETSESSION()->SyncExecute(_user->GetUserInfo().shard_Item_db_type, clsAuto))
		return;

//	// 현재 시간 기준 4시간 전
//	int subSec = (4 * 60 * 60);
//	time_t curTime = time(NULL);
//	time_t prevTime = curTime - subSec;
//
//	for (int i = 0; i < HasItemCount(); i++)
//	{
//		Item * pItem = _clsItemVector[i];
//		if (pItem == NULL)
//			continue;
//
//		if (pItem->GetData().reg_date >= prevTime)
//			continue;
//
//		if (pItem->GetData().eff_value[5] <= 0)
//			continue;
//
//		// 4시간 마다 1씩 감소
//		int subStamina = (curTime - pItem->GetData().reg_date) / subSec;
//
//		// 스태미너 차감
//		pItem->GetData().eff_value[5] -= subStamina;
//
//		if (pItem->GetData().eff_value[5] < 0)
//		{
//			pItem->GetData().eff_value[5] = 0;
//		}
//
//		pItem->GetData().reg_date = curTime;
//
//		pItem->UpdateDatabaseItemInfo();
//	}

}

} /*NLogic*/ } /* namespace ProjectZ */
